{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import argparse\n",
    "import os\n",
    "\n",
    "import PIL.Image\n",
    "import gradio as gr\n",
    "import huggingface_hub\n",
    "import numpy as np\n",
    "import onnxruntime as rt\n",
    "import pandas as pd\n",
    "from PIL import Image\n",
    "import PIL\n",
    "\n",
    "MODEL_FILENAME = \"model.onnx\"\n",
    "LABEL_FILENAME = \"selected_tags.csv\"\n",
    "MODEL_REPO = \"SmilingWolf/wd-swinv2-tagger-v3\"\n",
    "\n",
    "kaomojis = [\n",
    "    \"0_0\",\n",
    "    \"(o)_(o)\",\n",
    "    \"+_+\",\n",
    "    \"+_-\",\n",
    "    \"._.\",\n",
    "    \"<o>_<o>\",\n",
    "    \"<|>_<|>\",\n",
    "    \"=_=\",\n",
    "    \">_<\",\n",
    "    \"3_3\",\n",
    "    \"6_9\",\n",
    "    \">_o\",\n",
    "    \"@_@\",\n",
    "    \"^_^\",\n",
    "    \"o_o\",\n",
    "    \"u_u\",\n",
    "    \"x_x\",\n",
    "    \"|_|\",\n",
    "    \"||_||\",\n",
    "]\n",
    "\n",
    "def load_labels(dataframe) -> list[str]:\n",
    "    name_series = dataframe[\"name\"]\n",
    "    name_series = name_series.map(\n",
    "        lambda x: x.replace(\"_\", \" \") if x not in kaomojis else x\n",
    "    )\n",
    "    tag_names = name_series.tolist()\n",
    "\n",
    "    rating_indexes = list(np.where(dataframe[\"category\"] == 9)[0])\n",
    "    general_indexes = list(np.where(dataframe[\"category\"] == 0)[0])\n",
    "    character_indexes = list(np.where(dataframe[\"category\"] == 4)[0])\n",
    "    return tag_names, rating_indexes, general_indexes, character_indexes\n",
    "\n",
    "def mcut_threshold(probs):\n",
    "    \"\"\"\n",
    "    Maximum Cut Thresholding (MCut)\n",
    "    Largeron, C., Moulin, C., & Gery, M. (2012). MCut: A Thresholding Strategy\n",
    "     for Multi-label Classification. In 11th International Symposium, IDA 2012\n",
    "     (pp. 172-183).\n",
    "    \"\"\"\n",
    "    sorted_probs = probs[probs.argsort()[::-1]]\n",
    "    difs = sorted_probs[:-1] - sorted_probs[1:]\n",
    "    t = difs.argmax()\n",
    "    thresh = (sorted_probs[t] + sorted_probs[t + 1]) / 2\n",
    "    return thresh\n",
    "\n",
    "class Predictor:\n",
    "    def __init__(self):\n",
    "        self.model_target_size = None\n",
    "        self.last_loaded_repo = None\n",
    "        self.model = None\n",
    "\n",
    "    def download_model(self, model_repo):\n",
    "        csv_path = huggingface_hub.hf_hub_download(\n",
    "            model_repo,\n",
    "            LABEL_FILENAME,\n",
    "            use_auth_token=None,\n",
    "        )\n",
    "        model_path = huggingface_hub.hf_hub_download(\n",
    "            model_repo,\n",
    "            MODEL_FILENAME,\n",
    "            use_auth_token=None,\n",
    "        )\n",
    "        return csv_path, model_path\n",
    "\n",
    "    def load_model(self, model_repo):\n",
    "        if model_repo == self.last_loaded_repo:\n",
    "            return\n",
    "\n",
    "        csv_path, model_path = self.download_model(model_repo)\n",
    "\n",
    "        tags_df = pd.read_csv(csv_path)\n",
    "        sep_tags = load_labels(tags_df)\n",
    "\n",
    "        self.tag_names = sep_tags[0]\n",
    "        self.rating_indexes = sep_tags[1]\n",
    "        self.general_indexes = sep_tags[2]\n",
    "        self.character_indexes = sep_tags[3]\n",
    "\n",
    "        del self.model\n",
    "        model = rt.InferenceSession(model_path)\n",
    "        _, height, width, _ = model.get_inputs()[0].shape\n",
    "        self.model_target_size = height\n",
    "\n",
    "        self.last_loaded_repo = model_repo\n",
    "        self.model = model\n",
    "\n",
    "    def prepare_image(self, image: Image.Image):\n",
    "        target_size = self.model_target_size\n",
    "\n",
    "        canvas = Image.new(\"RGBA\", image.size, (255, 255, 255))\n",
    "        canvas.alpha_composite(image)\n",
    "        image = canvas.convert(\"RGB\")\n",
    "\n",
    "        # Pad image to square\n",
    "        image_shape = image.size\n",
    "        max_dim = max(image_shape)\n",
    "        pad_left = (max_dim - image_shape[0]) // 2\n",
    "        pad_top = (max_dim - image_shape[1]) // 2\n",
    "\n",
    "        padded_image = Image.new(\"RGB\", (max_dim, max_dim), (255, 255, 255))\n",
    "        padded_image.paste(image, (pad_left, pad_top))\n",
    "\n",
    "        # Resize\n",
    "        if max_dim != target_size:\n",
    "            padded_image = padded_image.resize(\n",
    "                (target_size, target_size),\n",
    "                Image.BICUBIC,\n",
    "            )\n",
    "\n",
    "        # Convert to numpy array\n",
    "        image_array = np.asarray(padded_image, dtype=np.float32)\n",
    "\n",
    "        # Convert PIL-native RGB to BGR\n",
    "        image_array = image_array[:, :, ::-1]\n",
    "\n",
    "        return np.expand_dims(image_array, axis=0)\n",
    "\n",
    "    def predict(\n",
    "        self,\n",
    "        image: Image.Image,\n",
    "        model_repo: str = \"SmilingWolf/wd-swinv2-tagger-v3\",\n",
    "        general_thresh=0.35,\n",
    "        general_mcut_enabled: bool=False,\n",
    "        character_thresh=0.85,\n",
    "        character_mcut_enabled: bool=False,\n",
    "    ):\n",
    "        self.load_model(model_repo)\n",
    "\n",
    "        image = self.prepare_image(image)\n",
    "\n",
    "        input_name = self.model.get_inputs()[0].name\n",
    "        label_name = self.model.get_outputs()[0].name\n",
    "        preds = self.model.run([label_name], {input_name: image})[0]\n",
    "\n",
    "        labels = list(zip(self.tag_names, preds[0].astype(float)))\n",
    "\n",
    "        # First 4 labels are actually ratings: pick one with argmax\n",
    "        ratings_names = [labels[i] for i in self.rating_indexes]\n",
    "        rating = dict(ratings_names)\n",
    "\n",
    "        # Then we have general tags: pick any where prediction confidence > threshold\n",
    "        general_names = [labels[i] for i in self.general_indexes]\n",
    "\n",
    "        if general_mcut_enabled:\n",
    "            general_probs = np.array([x[1] for x in general_names])\n",
    "            general_thresh = mcut_threshold(general_probs)\n",
    "\n",
    "        general_res = [x for x in general_names if x[1] > general_thresh]\n",
    "        general_res = dict(general_res)\n",
    "\n",
    "        # Everything else is characters: pick any where prediction confidence > threshold\n",
    "        character_names = [labels[i] for i in self.character_indexes]\n",
    "\n",
    "        if character_mcut_enabled:\n",
    "            character_probs = np.array([x[1] for x in character_names])\n",
    "            character_thresh = mcut_threshold(character_probs)\n",
    "            character_thresh = max(0.15, character_thresh)\n",
    "\n",
    "        character_res = [x for x in character_names if x[1] > character_thresh]\n",
    "        character_res = dict(character_res)\n",
    "\n",
    "        sorted_general_strings = sorted(\n",
    "            general_res.items(),\n",
    "            key=lambda x: x[1],\n",
    "            reverse=True,\n",
    "        )\n",
    "        sorted_general_strings = [x[0] for x in sorted_general_strings]\n",
    "        sorted_general_strings = (\n",
    "            \", \".join(sorted_general_strings).replace(\"(\", r\"\\(\").replace(\")\", r\"\\)\")\n",
    "        )\n",
    "\n",
    "        return sorted_general_strings, rating, character_res, general_res\n",
    "\n",
    "predictor = Predictor()\n",
    "img = Image.open(\"images/0.jpg\").convert(\"RGBA\")\n",
    "res = predictor.predict(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('1girl, greyscale, solo, monochrome, open mouth, school uniform, long hair, sailor collar, hair between eyes, serafuku, simple background, upper teeth only, blush, teeth, two side up, collarbone, shirt, looking at viewer, white background, ribbon, neckerchief, hair ribbon, round teeth, :o, eyelashes', {'general': np.float64(0.8988876342773438), 'sensitive': np.float64(0.10221874713897705), 'questionable': np.float64(0.0007412135601043701), 'explicit': np.float64(0.00011855363845825195)}, {}, {'1girl': np.float64(0.9962888956069946), 'solo': np.float64(0.9810552597045898), 'long hair': np.float64(0.9052051305770874), 'looking at viewer': np.float64(0.575506329536438), 'blush': np.float64(0.7980505228042603), 'open mouth': np.float64(0.9206589460372925), 'simple background': np.float64(0.8021034002304077), 'shirt': np.float64(0.6112005114555359), 'white background': np.float64(0.5420814752578735), 'ribbon': np.float64(0.5394940376281738), 'hair between eyes': np.float64(0.8546699285507202), 'school uniform': np.float64(0.9082940816879272), 'collarbone': np.float64(0.6788160800933838), 'monochrome': np.float64(0.9793205261230469), 'hair ribbon': np.float64(0.5145620107650757), 'greyscale': np.float64(0.9859572649002075), 'teeth': np.float64(0.7674233913421631), 'serafuku': np.float64(0.8057644367218018), 'sailor collar': np.float64(0.8644614815711975), ':o': np.float64(0.4390920102596283), 'two side up': np.float64(0.7467246055603027), 'neckerchief': np.float64(0.5178014039993286), 'eyelashes': np.float64(0.3877522349357605), 'upper teeth only': np.float64(0.801742672920227), 'round teeth': np.float64(0.45672792196273804)})\n"
     ]
    }
   ],
   "source": [
    "print(res)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载模型权重文件\n",
    "# openi model download BaiJin/diffusion pixel_lora --save_path ./pixel_lora\n",
    "torch.load('model.pth')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Config:\n",
    "    def __init__(self):\n",
    "        self.image_size=512\n",
    "        self.latent_size = 64\n",
    "        self.lr=0.02\n",
    "\n",
    "config = Config()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import CLIPTextModel, CLIPTokenizer,CLIPTextConfig\n",
    "tokenizer = CLIPTokenizer.from_pretrained(\"sd1.5/tokenizer/\")\n",
    "cfg = CLIPTextConfig.from_pretrained(\"sd1.5/text_encoder/\")\n",
    "text_encoder = CLIPTextModel(cfg)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 77, 768])\n"
     ]
    }
   ],
   "source": [
    "prompt = [\"a photograph of an astronaut riding a horse\"]\n",
    "text_input = tokenizer(prompt, padding=\"max_length\", max_length=tokenizer.model_max_length, truncation=True, return_tensors=\"pt\")\n",
    "text_embeddings = text_encoder(text_input.input_ids)[0]\n",
    "#text_embeddings = torch.randn(1, 77, 768)\n",
    "print(text_embeddings.shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "E:\\app\\python3\\lib\\site-packages\\diffusers\\configuration_utils.py:245: FutureWarning: It is deprecated to pass a pretrained model name or path to `from_config`.\n",
      "  deprecate(\"config-passed-as-path\", \"1.0.0\", deprecation_message, standard_warn=False)\n",
      "E:\\app\\python3\\lib\\site-packages\\diffusers\\configuration_utils.py:245: FutureWarning: It is deprecated to pass a pretrained model name or path to `from_config`.If you were trying to load a model, please use <class 'diffusers.models.unets.unet_2d_condition.UNet2DConditionModel'>.load_config(...) followed by <class 'diffusers.models.unets.unet_2d_condition.UNet2DConditionModel'>.from_config(...) instead. Otherwise, please make sure to pass a configuration dictionary instead. This functionality will be removed in v1.0.0.\n",
      "  deprecate(\"config-passed-as-path\", \"1.0.0\", deprecation_message, standard_warn=False)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'diffusers.models.unets.unet_2d_condition.UNet2DConditionModel'>\n"
     ]
    }
   ],
   "source": [
    "from diffusers import AutoencoderKL,UNet2DConditionModel\n",
    "vae = AutoencoderKL.from_config(\"sd1.5/vae/vae_config.json\")\n",
    "sd_model = UNet2DConditionModel.from_config(\"sd1.5/unet/unet_config.json\")\n",
    "print(type(sd_model))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'torch.Tensor'>\n",
      "torch.Size([1, 3, 512, 512])\n"
     ]
    }
   ],
   "source": [
    "# 用PIL加载图片\n",
    "from torchvision import transforms\n",
    "image = Image.open('images/2.jpg')\n",
    "\n",
    "# 定义转换操作\n",
    "transform = transforms.Compose([\n",
    "    transforms.Resize((config.image_size, config.image_size)),  # 将图片缩放到224*224\n",
    "    transforms.ToTensor()  # 将PIL Image或numpy.ndarray转换为Tensor，并自动将像素值缩放到[0, 1]并将通道维度提前\n",
    "\n",
    "])\n",
    " \n",
    "# 应用转换\n",
    "image_tensor = transform(image)\n",
    "image_tensor = image_tensor*2-1 # 放缩到(-1,1)\n",
    "image_tensor = image_tensor.unsqueeze(0)\n",
    " \n",
    "# 打印结果\n",
    "print(type(image_tensor))\n",
    "print(image_tensor.shape)  # 输出Tensor的形状"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'torch.Tensor'>\n",
      "torch.Size([1, 4, 64, 64])\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGBA size=64x64>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "latent = vae.encode(image_tensor).latent_dist.sample()\n",
    "print(type(latent))\n",
    "print(latent.shape)\n",
    "Image.fromarray(((latent.permute(0, 2, 3, 1) + 1.0) * 127.5).type(torch.uint8).numpy()[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1])\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGBA size=64x64>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 创建一个调度器\n",
    "from diffusers import DDPMScheduler,PNDMScheduler\n",
    "\n",
    "noise_scheduler = PNDMScheduler.from_pretrained(\"sd1.5/scheduler\")\n",
    "noise = torch.randn(latent.shape)\n",
    "timesteps = torch.LongTensor([100])\n",
    "print(timesteps.shape)\n",
    "noisy_latent = noise_scheduler.add_noise(latent, noise, timesteps)\n",
    "\n",
    "# 将加噪后的张量转换为标准的图像格式 [B,C,H,W]->[B,H,W,C], 张量值范围 [-1,1]->[0,2]->[0,255]\n",
    "Image.fromarray(((noisy_latent.permute(0, 2, 3, 1) + 1.0) * 127.5).type(torch.uint8).numpy()[0])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 优化器\n",
    "from diffusers.optimization import get_cosine_schedule_with_warmup\n",
    "optimizer = torch.optim.AdamW(sd_model.parameters(), lr=0.02)\n",
    "lr_scheduler = get_cosine_schedule_with_warmup(\n",
    "    optimizer=optimizer,\n",
    "    num_warmup_steps=10,\n",
    "    num_training_steps=100)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 包装器\n",
    "from accelerate import Accelerator\n",
    "accelerator = Accelerator(cpu=True)\n",
    "\n",
    "sd_model, optimizer, lr_scheduler = accelerator.prepare(sd_model, optimizer,lr_scheduler)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 4, 64, 64])\n",
      "torch.Size([1, 4, 64, 64])\n",
      "torch.Size([1, 4, 64, 64])\n"
     ]
    }
   ],
   "source": [
    "# 前向、反向传播、更新参数、更新学习率\n",
    "import torch.nn.functional as F\n",
    "print(noise.shape)\n",
    "print(noisy_latent.shape)\n",
    "noise_pred = sd_model(noisy_latent,timesteps,text_embeddings).sample\n",
    "\n",
    "loss = F.mse_loss(noise_pred, noise)\n",
    "#accelerator.backward(loss)\n",
    "loss.backward()\n",
    "optimizer.step()\n",
    "lr_scheduler.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "You have disabled the safety checker for <class 'diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline'> by passing `safety_checker=None`. Ensure that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered results in services or applications open to the public. Both the diffusers team and Hugging Face strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling it only for use-cases that involve analyzing network behavior or auditing its results. For more information, please have a look at https://github.com/huggingface/diffusers/pull/254 .\n"
     ]
    }
   ],
   "source": [
    "# 以diffusers库格式，保存模型\n",
    "from diffusers import StableDiffusionPipeline\n",
    "pipeline = StableDiffusionPipeline(\n",
    "    tokenizer=tokenizer,\n",
    "    text_encoder=text_encoder,\n",
    "    #unet=accelerator.unwrap_model(sd_model), \n",
    "    unet=sd_model, \n",
    "    scheduler=noise_scheduler,vae=vae,\n",
    "    safety_checker=None,\n",
    "    feature_extractor=None)\n",
    "pipeline = pipeline.save_pretrained(\"sd1.5\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "flowers",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
